﻿// Fill out your copyright notice in the Description page of Project Settings.


#include "BasicWidget.h"

#include "MathUtil.h"

TArray<FVector2D> UBasicWidget::GeneratePolynomialInterpolationPoint(TArray<FVector2D> input, int n)
{
	std::vector<Point> originalPoints;
	for (auto& point : input)
	{
		originalPoints.emplace_back(Point(point.X, point.Y));
	}
	Eigen::VectorXd polyCoeffs = polynomialInterpolation(originalPoints);
	auto polyFunc = [&](double x)
	{ 
		return evaluatePolynomial(polyCoeffs, x); 
	};
	std::vector<Point> polyFitPoints = generateFitPoints(polyFunc, originalPoints, n);
	TArray<FVector2D> res;
	for (auto& point : polyFitPoints)
	{
		res.Add(FVector2D(point.first, point.second));
	}
	return res;
}

TArray<FVector2D> UBasicWidget::GenerateGaussBasisInterpolationPoint(TArray<FVector2D> input, int n, double sigma, bool bUseAutoSigma)
{
	std::vector<Point> originalPoints;
	for (auto& point : input)
	{
		originalPoints.emplace_back(Point(point.X, point.Y));
	}

	sigma = bUseAutoSigma ? adaptiveGlobalSigma(originalPoints) : sigma;

	Eigen::VectorXd gaussCoeffs = gaussBasisInterpolation(originalPoints, sigma);
	auto gaussFunc = [&](double x)
	{
		return evaluateGaussBasis(gaussCoeffs, originalPoints, x, sigma);
	};
	std::vector<Point> gaussFitPoints = generateFitPoints(gaussFunc, originalPoints, n);
	TArray<FVector2D> res;
	for (auto& point : gaussFitPoints)
	{
		res.Add(FVector2D(point.first, point.second));
	}
	return res;
}

TArray<FVector2D> UBasicWidget::GeneratePolynomialFitPoint(TArray<FVector2D> input, int n, int m)
{
	std::vector<Point> originalPoints;
    for (auto& point : input)
    {
        originalPoints.emplace_back(Point(point.X, point.Y));
    }
    Eigen::VectorXd polyCoeffs = polynomialLeastSquaresFitting(originalPoints, m);
    auto polyFunc = [&](double x)
    {
        return evaluatePolynomial(polyCoeffs, x);
    };
    std::vector<Point> polyFitPoints = generateFitPoints(polyFunc, originalPoints, n);
    TArray<FVector2D> res;
    for (auto& point : polyFitPoints)
    {
        res.Add(FVector2D(point.first, point.second));
    }
    return res;
}

TArray<FVector2D> UBasicWidget::GenerateRidgeRegressionFitPoint(TArray<FVector2D> input, int n, int m, double lambda)
{
	std::vector<Point> originalPoints;
    for (auto& point : input)
    {
        originalPoints.emplace_back(Point(point.X, point.Y));
    }
    Eigen::VectorXd polyCoeffs = ridgeRegressionFitting(originalPoints, m, lambda);
    auto polyFunc = [&](double x)
    {
        return evaluatePolynomial(polyCoeffs, x);
    };
    std::vector<Point> polyFitPoints = generateFitPoints(polyFunc, originalPoints, n);
    TArray<FVector2D> res;
    for (auto& point : polyFitPoints)
    {
        res.Add(FVector2D(point.first, point.second));
    }
    return res;
}

TArray<FVector2D> UBasicWidget::GenerateParametricCurvePoint(TArray<FVector2D> input, int n, int m, EParametricTType type)
{
	std::vector<Point> originalPoints;
	for (auto& point : input)
	{
		originalPoints.emplace_back(Point(point.X, point.Y));
	}
	std::vector<double> t;
	switch (type)
	{
	case EParametricTType::EquidistantT:
        t = generateEquidistantT(originalPoints);
		break;
	case EParametricTType::ChordLengthT:
        t = generateChordLengthT(originalPoints);
		break;
	case EParametricTType::CentripetalT:
        t = generateCentripetalT(originalPoints);
		break;
	case EParametricTType::FoleyT:
        t = generateFoleyT(originalPoints);
		break;
	default:
		break;
	}

	if (t.empty()) return TArray<FVector2D>();

	auto coeffs = fitParametricLeastSquares(originalPoints, m, t);
	float step = 1.0f / n;
	std::vector<Point> fitPoints;
	for (float i = 0;i < 1.f;i += step)
	{
		fitPoints.emplace_back(evaluateFittedCurve(i, coeffs));
	}

    TArray<FVector2D> res;
    for (auto& point : fitPoints)
    {
        res.Add(FVector2D(point.first, point.second));
    }

	return res;
}
